{
 "cells": [
  {
   "cell_type": "code",
   "id": "777b47454f7d860b_setup",
   "metadata": {},
   "source": [
    "from pprint import pprint\n",
    "\n",
    "from sagemaker.core.resources import TrainingJob, HubContent, InferenceComponent, ModelPackage\n",
    "from sagemaker.core.utils.utils import Unassigned\n",
    "! ada credentials update --provider=isengard --account=<> --role=Admin --profile=default --once\n",
    "! aws configure set region  us-west-2"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "da22762d06751e9b",
   "metadata": {},
   "source": [
    "from sagemaker.core.resources import Endpoint\n",
    "\n",
    "# Delete endpoints starting with 'e2e-'\n",
    "for endpoint in Endpoint.get_all():\n",
    "    if endpoint.endpoint_name.startswith('e2e-'):\n",
    "        endpoint.delete()\n"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "95367703",
   "metadata": {},
   "source": [
    "from sagemaker.core.resources import TrainingJob, HubContent, InferenceComponent, ModelPackage\n",
    "from sagemaker.core.utils.utils import Unassigned\n",
    "\n",
    "for training_job in TrainingJob.get_all(region=\"us-west-2\"):\n",
    "    if not isinstance(training_job.output_model_package_arn, Unassigned):\n",
    "        try:\n",
    "            model_package = ModelPackage.get(training_job.output_model_package_arn)\n",
    "            if not isinstance(model_package.inference_specification.containers[0].image,Unassigned)\\\n",
    "                    and model_package.inference_specification.containers[0].image is not None:\n",
    "                print(training_job.training_job_arn)\n",
    "                print(model_package.inference_specification.containers[0].image)\n",
    "        except:\n",
    "            pass\n"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "from sagemaker.core.resources import TrainingJob\n",
    "import random\n",
    "training_job = TrainingJob.get(training_job_name=\"meta-textgeneration-llama-3-2-1b-instruct-sft-20251123162832\")\n",
    "print(training_job.output_model_package_arn)\n",
    "name = f\"e2e-{random.randint(100, 10000)}\"\n",
    "from sagemaker.serve import ModelBuilder\n",
    "model_builder = ModelBuilder(model=training_job)\n",
    "model = model_builder.build(model_name=name)\n",
    "print(model.model_arn)\n",
    "import random\n",
    "#endpoint = model_builder.deploy(endpoint_name=name)"
   ],
   "id": "2415b1cb715a304c",
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": "endpoint = model_builder.deploy(endpoint_name=name)",
   "id": "8b8bc9eb4299ecba",
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "from sagemaker.core.resources import InferenceComponent, Tag\n",
    "from pprint import pprint\n",
    "\n",
    "for inference_component in InferenceComponent.get_all(endpoint_name_equals=\"e2e-2358\"):\n",
    "    print(inference_component.inference_component_arn)\n",
    "    for tag in Tag.get_all(resource_arn=inference_component.inference_component_arn):\n",
    "        pprint(tag)\n",
    "\n"
   ],
   "id": "58b5d5995791bd96",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "2833eab06285f075",
   "metadata": {},
   "source": [
    "import json\n",
    "# Note this is expected to fail since Endpoint invoke is only available for authorized users. The Invoke call here is the sagemaker-core Endpoint.invoke call .\n",
    "print(endpoint.endpoint_arn)\n",
    "endpoint.invoke(body=json.dumps({\"inputs\": \"What is the capital of France?\", \"parameters\": {\"max_new_tokens\": 50}}))"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "695a83cf38e46cea",
   "metadata": {},
   "source": [
    "from sagemaker.core.resources import TrainingJob\n",
    "from sagemaker.serve import ModelBuilder\n",
    "\n",
    "model_builder = ModelBuilder(model=TrainingJob.get(training_job_name=\"meta-textgeneration-llama-3-2-1b-instruct-sft-20251123162832\"))\n",
    "model_builder.fetch_endpoint_names_for_base_model()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "92e0da7904ffb743",
   "metadata": {},
   "source": [
    "name = f\"e2e-{random.randint(100, 10000)}\"\n",
    "model_builder.name = name\n",
    "endpoint = model_builder.deploy(endpoint_name=name, inference_component_name=f\"{name}-adapter\")\n",
    "sda"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "intro_modelpackage",
   "metadata": {},
   "source": [
    "## Part 2: Deploy from ModelPackage\n",
    "\n",
    "This section demonstrates an alternative deployment workflow using SageMaker Model Registry. This approach is ideal for production environments where:\n",
    "\n",
    "**Model Registry Benefits:**\n",
    "- **Version Control**: Track multiple versions of your models\n",
    "- **Governance**: Implement approval workflows before deployment\n",
    "- **Reproducibility**: Deploy the exact same model version across environments\n",
    "- **Metadata Management**: Store model metrics, lineage, and documentation\n",
    "- **CI/CD Integration**: Automate deployment pipelines with versioned artifacts\n",
    "\n",
    "**When to Use ModelPackages:**\n",
    "- Production deployments requiring approval gates\n",
    "- Multi-environment deployments (dev, staging, prod)\n",
    "- Models shared across teams or accounts\n",
    "- Compliance and audit requirements\n",
    "\n",
    "ModelPackages are automatically created when training jobs complete, or can be registered manually."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "modelpackage_create",
   "metadata": {},
   "source": [
    "### Create ModelPackage Resource\n",
    "\n",
    "Instantiate a ModelPackage resource from the SageMaker Model Registry. This represents a versioned, registered model with:\n",
    "\n",
    "**ModelPackage Metadata:**\n",
    "- **Group**: 'test-finetuned-models' (collection of related model versions)\n",
    "- **Version**: 3 (specific iteration of the fine-tuned model)\n",
    "- **Status**: Completed (ready for deployment)\n",
    "\n",
    "**Inference Specification:**\n",
    "- Model artifacts location in S3\n",
    "- Base model reference (Llama 3.2 1B Instruct v0.0.3)\n",
    "- Recipe name for fine-tuning configuration\n",
    "- Container and runtime requirements\n",
    "\n",
    "This ModelPackage was automatically created by the training job in Part 1, demonstrating the integration between training and model registry."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "modelbuilder_modelpackage",
   "metadata": {},
   "source": [
    "### Build Model from ModelPackage\n",
    "\n",
    "Use ModelBuilder with a ModelPackage resource instead of a TrainingJob. The process is similar but with key differences:\n",
    "\n",
    "**ModelPackage vs TrainingJob Deployment:**\n",
    "- **ModelPackage**: Uses versioned, approved artifacts from Model Registry\n",
    "- **TrainingJob**: Uses artifacts directly from training output\n",
    "\n",
    "**Advantages of ModelPackage Approach:**\n",
    "- Deploy any approved version, not just the latest training run\n",
    "- Rollback to previous versions easily\n",
    "- Deploy the same version across multiple environments\n",
    "- Leverage approval workflows and governance policies\n",
    "\n",
    "ModelBuilder automatically resolves all necessary metadata from the ModelPackage, including model artifacts, base model references, and inference configurations."
   ]
  },
  {
   "cell_type": "code",
   "id": "778be153d0a87d13",
   "metadata": {},
   "source": [
    "import random\n",
    "from sagemaker.serve import ModelBuilder\n",
    "\n",
    "from sagemaker.core.resources import ModelPackage\n",
    "\n",
    "name = f\"e2e-{random.randint(100, 1000000)}\"\n",
    "model_package = ModelPackage.get(model_package_name=\"arn:aws:sagemaker:us-west-2:<>:model-package/test-finetuned-models-gamma/68\")\n",
    "model_builder = ModelBuilder(model=model_package)\n",
    "model_builder.build()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "deploy_modelpackage",
   "metadata": {},
   "source": [
    "### Deploy ModelPackage to Endpoint\n",
    "\n",
    "Deploy the versioned ModelPackage to a new SageMaker real-time endpoint. This deployment:\n",
    "\n",
    "**Deployment Characteristics:**\n",
    "- Uses the exact model version specified in the ModelPackage\n",
    "- Maintains full traceability to the original training job\n",
    "- Can be deployed to multiple endpoints simultaneously\n",
    "- Supports the same deployment patterns (standalone or multi-adapter)\n",
    "\n",
    "**Production Best Practices:**\n",
    "- Use ModelPackages for all production deployments\n",
    "- Implement approval workflows before deployment\n",
    "- Tag endpoints with model version for tracking\n",
    "- Monitor model performance and drift\n",
    "\n",
    "The deployment process is identical to Part 1, but with the confidence that you're deploying a versioned, approved model artifact."
   ]
  },
  {
   "cell_type": "code",
   "id": "ef3384c868dd58d5",
   "metadata": {},
   "source": "endpoint = model_builder.deploy( endpoint_name=name)\n",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "ee4ba6c06033fe08",
   "metadata": {},
   "source": [
    "## Bedrock Model Builder\n"
   ]
  },
  {
   "cell_type": "code",
   "id": "d17136303e9b7c9e",
   "metadata": {},
   "source": [
    "import boto3\n",
    "import json\n",
    "\n",
    "# Create config.json for Llama 3.2 1B model\n",
    "config = {\n",
    "    \"architectures\": [\"LlamaForCausalLM\"],\n",
    "    \"attention_bias\": False,\n",
    "    \"attention_dropout\": 0.0,\n",
    "    \"bos_token_id\": 128000,\n",
    "    \"eos_token_id\": 128001,\n",
    "    \"hidden_act\": \"silu\",\n",
    "    \"hidden_size\": 2048,\n",
    "    \"initializer_range\": 0.02,\n",
    "    \"intermediate_size\": 8192,\n",
    "    \"max_position_embeddings\": 131072,\n",
    "    \"model_type\": \"llama\",\n",
    "    \"num_attention_heads\": 32,\n",
    "    \"num_hidden_layers\": 16,\n",
    "    \"num_key_value_heads\": 8,\n",
    "    \"pretraining_tp\": 1,\n",
    "    \"rms_norm_eps\": 1e-05,\n",
    "    \"rope_scaling\": None,\n",
    "    \"rope_theta\": 500000.0,\n",
    "    \"tie_word_embeddings\": True,\n",
    "    \"torch_dtype\": \"bfloat16\",\n",
    "    \"transformers_version\": \"4.45.0\",\n",
    "    \"use_cache\": True,\n",
    "    \"vocab_size\": 128256\n",
    "}\n",
    "\n",
    "# Upload to S3\n",
    "s3 = boto3.client('s3')\n",
    "s3.put_object(\n",
    "    Bucket='open-models-testing-pdx',\n",
    "    Key='output/meta-textgeneration-llama-3-2-1b-instruct-sft-20251114104310/output/model/config.json',\n",
    "    Body=json.dumps(config, indent=2),\n",
    "    ContentType='application/json'\n",
    ")\n",
    "\n",
    "print(\"config.json uploaded successfully\")\n"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "865777e899016a07",
   "metadata": {},
   "source": [
    "import boto3\n",
    "import json\n",
    "\n",
    "s3 = boto3.client('s3', region_name='us-west-2')\n",
    "config = {\"add_bos_token\": True, \"add_eos_token\": False, \"bos_token\": \"<|begin_of_text|>\", \"eos_token\": \"<|end_of_text|>\", \"pad_token\": \"<|end_of_text|>\", \"model_max_length\": 131072, \"tokenizer_class\": \"LlamaTokenizer\"}\n",
    "s3.put_object(Bucket=\"open-models-testing-pdx\", Key=\"output/meta-textgeneration-llama-3-2-1b-instruct-sft-20251114104310/output/model/tokenizer_config.json\", Body=json.dumps(config))\n"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "533d0f1022d169eb",
   "metadata": {},
   "source": [
    "! ada credentials update --provider=isengard --account=<> --role=Admin --profile=default --once\n"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "798f5b8668305f43",
   "metadata": {},
   "source": [
    "from sagemaker.core.resources import TrainingJob\n",
    "import random\n",
    "\n",
    "\n",
    "training_job = TrainingJob.get(training_job_name=\"11-21-llama33-70b-bbh-v1-2025-11-21-18-47-09-200\", region=\"us-west-2\")\n",
    "name = f\"e2e-{random.randint(100, 10000)}\"\n",
    "\n",
    "# bedrock_builder = BedrockModelBuilder(model=training_job)\n",
    "# bedrock_builder.deploy(job_name=name, imported_model_name=name, role_arn=\"arn:aws:iam::<>:role/Admin\")"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "6fdd61406713c8c9",
   "metadata": {},
   "source": [
    "# Assuming you previously did something like:\n",
    "# bedrock_builder = BedrockModelBuilder(model_trainer)\n",
    "# import_response = bedrock_builder.deploy(imported_model_name=\"my-custom-model-name\", ...)\n",
    "\n",
    "# Use the imported_model_name as the modelId for Bedrock inference\n",
    "bedrock_runtime = boto3.client('bedrock-runtime', region_name='us-west-2')\n",
    "\n",
    "response = bedrock_runtime.invoke_model(\n",
    "    modelId=name,  # This is the imported_model_name from your deploy call\n",
    "    body=json.dumps({\n",
    "        \"inputText\": \"What is the capital of France?\",\n",
    "        \"textGenerationConfig\": {\n",
    "            \"maxTokenCount\": 50\n",
    "        }\n",
    "    })\n",
    ")\n"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "summary_section",
   "metadata": {},
   "source": [
    "## Summary\n",
    "\n",
    "This notebook provided a comprehensive guide to deploying fine-tuned LLMs on Amazon SageMaker using two distinct workflows:\n",
    "\n",
    "### Key Takeaways\n",
    "\n",
    "**Deployment Approaches:**\n",
    "1. **TrainingJob → Endpoint**: Direct deployment for rapid iteration and testing\n",
    "2. **ModelPackage → Endpoint**: Versioned deployment for production governance\n",
    "\n",
    "**Deployment Patterns:**\n",
    "- **Standalone Endpoints**: Dedicated resources, full isolation, simple management\n",
    "- **Multi-Adapter Endpoints**: Shared base model, cost-efficient, dynamic routing\n",
    "\n",
    "**Best Practices:**\n",
    "- Use TrainingJob deployment for development and experimentation\n",
    "- Use ModelPackage deployment for production with approval workflows\n",
    "- Leverage multi-adapter deployment to reduce costs when serving multiple variants\n",
    "- Always test endpoints with sample requests before production traffic\n",
    "\n",
    "**Next Steps:**\n",
    "- Implement monitoring and logging for production endpoints\n",
    "- Set up auto-scaling policies based on traffic patterns\n",
    "- Create CI/CD pipelines for automated model deployment\n",
    "- Explore model monitoring for drift detection and performance tracking"
   ]
  },
  {
   "cell_type": "code",
   "id": "aefa0ec7cd360d5c",
   "metadata": {},
   "source": [
    "import boto3\n",
    "\n",
    "bedrock = boto3.client('bedrock', region_name='us-west-2')\n",
    "\n",
    "# List and delete model import jobs\n",
    "import_jobs = bedrock.list_model_import_jobs()\n",
    "for job in import_jobs['modelImportJobSummaries']:\n",
    "    job_arn = job['jobArn']\n",
    "    print(f\"Deleting import job: {job_arn}\")\n",
    "    # Note: Import jobs auto-cleanup, but you can stop in-progress ones\n",
    "    if job['status'] in ['InProgress', 'Submitted']:\n",
    "        bedrock.stop_model_import_job(jobIdentifier=job_arn)\n",
    "\n",
    "# List and delete imported models\n",
    "imported_models = bedrock.list_imported_models()\n",
    "for model in imported_models['modelSummaries']:\n",
    "    model_arn = model['modelArn']\n",
    "    print(f\"Deleting imported model: {model_arn}\")\n",
    "    bedrock.delete_imported_model(modelIdentifier=model_arn)\n"
   ],
   "outputs": [],
   "execution_count": null
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
